home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src.arc / AX_MBX.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  16KB  |  641 lines

  1. /* There are only two functions in this mailbox code that depend on the
  2.    underlying protocol, namely mbx_getname() and dochat(). All the other
  3.    functions can hopefully be used without modification on other stream
  4.    oriented protocols than AX.25 or NET/ROM.
  5.    However, please note that on AX.25 '\r' is used as EOL character while
  6.    on for instance TCP, '\r\n' is used. It would be handy if there were
  7.    a printf-compatible function that would take '\n' and map it to whatever
  8.    is the convention for the particular protocol in use.
  9.    SM0RGV 890506, most work done previously by W9NK
  10.  */
  11. #include <stdio.h>
  12. #include <time.h>
  13. #include <ctype.h>
  14. #ifdef    UNIX
  15. #include <sys/types.h>
  16. #endif
  17. #include "global.h"
  18. #include "ax_mbx.h"
  19. #include "cmdparse.h"
  20. #include "proc.h"
  21. #include "socket.h"
  22. #include "usock.h"
  23. #include "ax25.h"
  24. #include "smtp.h"
  25.  
  26. /*
  27. #define MBDEBUG
  28. */
  29.  
  30. static struct mbx *Mbox[NUMMBX] ;
  31. int Ax25mbox ;
  32.  
  33. static char Mbbanner[] = "[NET-$]\rWelcome to the %s TCP/IP Mailbox\r%s";
  34. static char Mbmenu[] = "(C)hat, (S)end, (B)ye >\r" ;
  35.  
  36. static int donothing __ARGS((int argc,char *argv[],void *p));
  37. static int dosend __ARGS((int argc,char *argv[],void *p));
  38. static int dochat __ARGS((int argc,char *argv[],void *p));
  39. static void domboxdisplay __ARGS((void));
  40. static int dosid __ARGS((int argc,char *argv[],void *p));
  41. static int dorevfwd __ARGS((int argc,char *argv[],void *p));
  42. static struct mbx *newmbx __ARGS((void));
  43. static int mbx_parse __ARGS((struct mbx *m));
  44. static void mbx_getname __ARGS((struct mbx *m));
  45. static int dobye __ARGS((int argc,char *argv[],void *p));
  46. static int mbx_to __ARGS((int argc,char *argv[],void *p));
  47. static int mbx_data __ARGS((struct mbx *m));
  48.  
  49. static struct cmds Mbcmds[] = {
  50.     "",        donothing,    0, 0, NULLCHAR,
  51.     "s",        dosend,        0, 0, NULLCHAR,
  52.     "send",        dosend,        0, 0, NULLCHAR,
  53.     "chat",        dochat,        0, 0, NULLCHAR,
  54.     "bye",        dobye,        0, 0, NULLCHAR,
  55.     "[",        dosid,        0, 0, NULLCHAR,
  56.     "f>",        dorevfwd,    0, 0, NULLCHAR,
  57.     NULLCHAR,    NULLFP,        0, 0, NULLCHAR,
  58. };
  59.  
  60. int
  61. dombox(argc, argv,p)
  62. int argc ;
  63. char *argv[] ;
  64. void *p;
  65. {
  66.     setbool(&Ax25mbox,"AX25 mailbox",argc,argv);
  67.     if (argc < 2)
  68.         domboxdisplay() ;
  69.     return 0;
  70. }
  71.  
  72. static void
  73. domboxdisplay()
  74. {
  75.     int i ;
  76.     struct mbx *m ;
  77.     static char *states[] = {"NONE","CMD","SUBJ","DATA"} ;
  78.  
  79.     printf("User       State    Type     S#\n");
  80.  
  81.     for (i = 0 ; i < NUMMBX ; i++)
  82.         if ((m = Mbox[i]) != NULLMBX) {
  83.             printf("%-10s %-4s     %-7s  %-3u\n",m->name,
  84.              states[m->state],Sestypes[m->type],m->user);
  85.         }
  86. }
  87.  
  88. static struct mbx *
  89. newmbx()
  90. {
  91.     int i ;
  92.     struct mbx *m ;
  93.  
  94.     for (i = 0 ; i < NUMMBX ; i++)
  95.         if (Mbox[i] == NULLMBX) {
  96.             if ((m = Mbox[i] = (struct mbx *)calloc(1,sizeof(struct mbx)))
  97.                 == NULLMBX)
  98.                 return NULLMBX ;
  99.             m->mbnum = i ;
  100.             return m ;
  101.         }
  102.  
  103.     /* If we get here, there are no free mailbox sessions */
  104.  
  105.     return NULLMBX ;
  106. }
  107.  
  108. /* Incoming mailbox session */
  109.  
  110. void
  111. mbx_incom(s,t,p)
  112. int s;
  113. void *t;
  114. void *p;
  115. {
  116.     int type;            /* type of session when invoking "chat" */
  117.     int i;
  118.     char buf[30];
  119.     struct mbx *m ;
  120.     
  121.     type = (int)t;
  122.     sockowner(s,Curproc);    /* We own it now */
  123.     sprintf(buf,"open %s MBOX",Sestypes[type]);
  124.     log(s,buf);
  125.     if ((m = newmbx()) == NULLMBX) {
  126.         usprintf(s,"Too many mailbox sessions\r");
  127.         close_s(s) ;    /* no memory! */
  128.         return ;
  129.     }
  130.     m->user = s;
  131.     m->type = type;
  132.     m->state = MBX_CMD ;    /* start in command state */
  133.     mbx_getname(m);        /* get the name of the remote station */
  134.  
  135.     /* Now say hi */
  136.     usprintf(s,Mbbanner,Hostname,Mbmenu);
  137.     while (recvline(s,m->line,MBXLINE) != -1) {
  138.         if (m->line[0] != '\n' && m->line[0] != '\r'){
  139.             i = mbx_parse(m);
  140.                 if (i == -1)
  141.                 usprintf(s,"Huh?\r");
  142.             if (i == 1)
  143.                 usprintf(s,"Bad syntax.\r");
  144.         }
  145.         usprintf(s,(m->sid & MBX_SID) ? ">\r" : Mbmenu);
  146.         m->state = MBX_CMD;
  147.     }
  148.     free(m->to) ;
  149.     free(m->tofrom) ;
  150.     free(m->tomsgid) ;
  151.     Mbox[m->mbnum] = NULLMBX ;
  152.     free((char *)m) ;
  153. }
  154.  
  155. /* "twocmds" defines the MBL/RLI two-letter commands, eg. "SB", "SP" and so on.
  156.    They have to be treated specially since cmdparse() wants a space between
  157.    the actual command and its arguments.
  158.    "SP FOO" is converted to "s  foo" and the second command letter is saved
  159.    in m->stype. Longer commands like "SEND" are unaffected, except for
  160.    commands starting with "[", i.e. the SID, since we don't know what it will
  161.    look like.
  162.  */
  163. static char twocmds[] = "slrn[";    /* S,L,R,N are two-letter commands */
  164. static int
  165. mbx_parse(m)
  166. struct mbx *m;
  167. {
  168.     char *cp;
  169.     int i;
  170.     /* Translate entire buffer to lower case */
  171.     for (cp = m->line; *cp != '\0'; ++cp)
  172.     if (isupper(*cp))
  173.         *cp = tolower(*cp);
  174.     for (cp = m->line;isspace(*cp);++cp) ;/* Skip any spaces at the begining */
  175.     m->stype = ' ';
  176.     if (*cp != '\0' && *(cp+1) != '\0')
  177.     for(i=0; i<strlen(twocmds); ++i)
  178.         if (*cp == twocmds[i] && (isspace(*(cp+2)) || *(cp+2) == '\0'
  179.                       || *cp == '[')) {
  180.         if (islower(*(++cp)))
  181.             m->stype = toupper(*cp); /* Save the second character */
  182.         else m->stype = *cp;
  183.         *cp = ' ';
  184.         break;
  185.         }
  186.     return cmdparse(Mbcmds,m->line,(void *)m);
  187. }
  188.  
  189. static void
  190. mbx_getname(m)
  191. struct mbx *m;
  192. {
  193.     char *cp;
  194.     union sp sp;
  195.     char tmp[MAXSOCKSIZE];
  196.     int len = MAXSOCKSIZE;
  197.     
  198.     getpeername(m->user,tmp,&len);
  199.     /* This is one of the two parts of the mbox code that depends on the
  200.        underlying protocol. We have to figure out the name of the
  201.        calling station. This is only practical when AX.25 or NET/ROM
  202.        is used. If we were using the mbox with TCP/IP one would
  203.        rather have to login in a manner similar to ftp.
  204.      */
  205.     sp.p = tmp;
  206.     switch(sp.sa->sa_family){
  207.     case AF_NETROM:
  208.     case AF_AX25:
  209.     /* NETROM and AX25 socket address structures are "compatible" */
  210.     pax25(m->name,&sp.ax->ax25_addr) ;
  211.     cp = strchr(m->name,'-') ;
  212.     if (cp != NULLCHAR)            /* get rid of SSID */
  213.         *cp = '\0' ;
  214. /*  case AF_INET: We need a gethostbyaddr() or login procedure first */        
  215.     }
  216. }
  217.  
  218. static int
  219. dobye(argc,argv,p)
  220. int argc;
  221. char *argv[];
  222. void *p;
  223. {
  224.     struct mbx *m;
  225.  
  226.     m = (struct mbx *)p;
  227.     close_s(m->user);
  228.     return 0;
  229. }
  230. static int
  231. dochat(argc,argv,p)
  232. int argc;
  233. char *argv[];
  234. void *p;
  235. {
  236.     struct mbx *m;
  237.     struct proc *pp;
  238.  
  239.     m = (struct mbx *)p;
  240.     pp = newproc("in_chat",2048,axnrhandle,m->user,(void *)m->type,NULL);
  241.     pwait(pp);
  242.     /* It returns only after a disconnect */
  243.     return 0;
  244. }
  245.  
  246. /* Called every time a blank line is received. */
  247. static int
  248. donothing(argc,argv,p)
  249. int argc;
  250. char *argv[];
  251. void *p;
  252. {
  253.     return 0;
  254. }
  255.  
  256. static int
  257. dosend(argc,argv,p)
  258. int argc;
  259. char *argv[];
  260. void *p;
  261. {
  262.     int s;
  263.     char *host,fullfrom[80];
  264.     struct mbx *m;
  265.  
  266.     m = (struct mbx *)p;
  267.     s = m->user;
  268.     if (mbx_to(argc,argv,m) == -1) {
  269.         if (m->sid & MBX_SID)
  270.             usprintf(s,"NO - syntax error\r") ;
  271.         else {
  272.             usprintf(s,"S command syntax error - format is:\r");
  273.             usprintf(s,"  S name [@ host] [< from_addr] [$bulletin_id]\r");
  274.         }
  275.         return 0;
  276.     }
  277.     if (validate_address(m->to) == 0){
  278.         if (m->sid & MBX_SID)
  279.             usprintf(s, "NO - bad address\r");
  280.         else
  281.             usprintf(s, "Bad user or host name\r");
  282.         /* We don't free any buffers here. They are freed upon the next
  283.          * call to mbx_to() or to dobye()
  284.          */
  285.         return 0;
  286.     }
  287.     m->state = MBX_SUBJ ;
  288.     usprintf(s,    (m->sid & MBX_SID) ? "OK\r" : "Subject:\r");
  289.     if (recvline(s,m->line,MBXLINE) == -1)
  290.         return 0;
  291.     rip(m->line);
  292.     if (mbx_data(m) == -1) {
  293.         usprintf(s,"Can't create temp file for mail\r") ;
  294.         return 0 ;
  295.     }
  296.     m->state = MBX_DATA ;
  297.     if ((m->sid & MBX_SID) == 0)
  298.         usprintf(s,
  299.          "Enter message.  Terminate with /EX or ^Z in first column:\r");
  300.  
  301.     while (recvline(s,m->line,MBXLINE) != -1) {
  302.         rip(m->line);
  303.         if (m->line[0] == 0x1a ||
  304.          strcmp(m->line, "/ex") == 0 ||
  305.          strcmp(m->line, "/EX") == 0) {
  306.             if ((host = strchr(m->to,'@')) == NULLCHAR)
  307.                 host = Hostname ;    /* use our hostname */
  308.             else
  309.                 host++ ;        /* use the host part of address */
  310.         
  311.             /* make up full from name for work file */
  312.             (void)sprintf(fullfrom,"%s@%s",m->name,Hostname) ;
  313.             fseek(m->tfile,0L,0) ;        /* reset to beginning */
  314.             if (queuejob(m->tfile,host,m->to,fullfrom) != 0)
  315.                 usprintf(s, "Couldn't queue message for delivery\r");
  316.             break;
  317.         } else
  318.             fprintf(m->tfile,"%s\n",m->line) ;        /* not done yet! */
  319.     }
  320.     fclose(m->tfile) ;
  321.     return 0 ;
  322. }
  323.  
  324. static int
  325. dosid(argc,argv,p)
  326. int argc;
  327. char *argv[];
  328. void *p;
  329. {
  330.     struct mbx *m;
  331.  
  332.     m = (struct mbx *)p;
  333.     if (argc == 1)
  334.         return 1;
  335.     if (argv[1][strlen(argv[1]) - 1] != ']') /* must be an SID */
  336.         return 1;
  337.     m->sid = MBX_SID ;
  338.     /* Now check to see if this is an RLI board.
  339.      * As usual, Hank does it a bit differently from
  340.      * the rest of the world.
  341.      */
  342.     if(m->stype == 'R' && strncmp(argv[1],"li",2) == 0)/* [RLI] at a minimum */
  343.         m->sid |= MBX_SID_RLI ;
  344.     return 0;
  345. }
  346.  
  347. static int
  348. dorevfwd(argc,argv,p)
  349. int argc;
  350. char *argv[];
  351. void *p;
  352.  
  353. {
  354.     struct mbx *m;
  355.  
  356.     m = (struct mbx *)p;
  357.     if (m->sid & MBX_SID) {
  358.         /* RLI BBS' expect us to disconnect if we
  359.          * have no mail for them, which of course
  360.          * we don't, being rather haughty about our
  361.          * protocol superiority.
  362.          */
  363.         if (m->sid & MBX_SID_RLI)
  364.             dobye(0,NULL,m) ;
  365.         return 0;
  366.     }
  367.     return -1;
  368. }
  369.  
  370. /* States for send line parser state machine */
  371.  
  372. #define        LOOK_FOR_USER        2
  373. #define        IN_USER            3
  374. #define        AFTER_USER        4
  375. #define        LOOK_FOR_HOST        5
  376. #define        IN_HOST            6
  377. #define        AFTER_HOST        7
  378. #define        LOOK_FOR_FROM        8
  379. #define        IN_FROM            9
  380. #define        AFTER_FROM        10
  381. #define        LOOK_FOR_MSGID        11
  382. #define        IN_MSGID        12
  383. #define        FINAL_STATE        13
  384. #define        ERROR_STATE        14
  385.  
  386. /* Prepare the addressee.  If the address is bad, return -1, otherwise
  387.  * return 0
  388.  */
  389. static int
  390. mbx_to(argc,argv,p)
  391. int argc;
  392. char *argv[];
  393. void *p;
  394. {
  395.     register char *cp;
  396.     int state, i ;
  397.     char *user, *host, *from, *msgid ;
  398.     int userlen = 0, hostlen = 0, fromlen = 0, msgidlen = 0 ;
  399.     struct mbx *m ;
  400.     
  401.     m = (struct mbx *)p;
  402.     /* Free anything that might be allocated
  403.      * since the last call to mbx_to()
  404.      */
  405.     free(m->to) ;
  406.     m->to = NULLCHAR ;
  407.     free(m->tofrom) ;
  408.     m->tofrom = NULLCHAR ;
  409.     free(m->tomsgid) ;
  410.     m->tomsgid = NULLCHAR ;
  411.  
  412.     if (argc == 1)
  413.         return -1;
  414.     i = 1;
  415.     cp = argv[i];
  416.     state = LOOK_FOR_USER ;
  417.     while (state < FINAL_STATE) {
  418. #ifdef MBDEBUG
  419.         printf("State is %d, char is %c\n", state, *cp) ;
  420. #endif
  421.         switch (state) {
  422.         case LOOK_FOR_USER:
  423.             if (*cp == '@' || *cp == '<' || *cp == '$')
  424.                 state = ERROR_STATE ;        /* no user */
  425.             else {
  426.                 user = cp ;            /* point at start */
  427.                 userlen++ ;            /* start counting */
  428.                 state = IN_USER ;
  429.             }
  430.             break ;
  431.         case IN_USER:
  432.             switch (*cp) {
  433.             case '\0':
  434.                 state = AFTER_USER ;        /* done with username */
  435.                 break ;
  436.             case '@':
  437.                 state = LOOK_FOR_HOST ;        /* hostname should follow */
  438.                 break ;
  439.             case '<':
  440.                 state = LOOK_FOR_FROM ;        /* from name should follow */
  441.                 break ;
  442.             case '$':
  443.                 state = LOOK_FOR_MSGID ;    /* message id should follow */
  444.                 break ;
  445.             default:
  446.                 userlen++ ;            /* part of username */
  447.             }
  448.             break ;
  449.         case AFTER_USER:
  450.             switch (*cp) {
  451.             case '@':
  452.                 state = LOOK_FOR_HOST ;        /* hostname follows */
  453.                 break ;
  454.             case '<':
  455.                 state = LOOK_FOR_FROM ;        /* fromname follows */
  456.                 break ;
  457.             case '$':
  458.             state = LOOK_FOR_MSGID ;    /* message id follows */
  459.                 break ;
  460.             default:
  461.                 state = ERROR_STATE ;
  462.             }
  463.             break ;
  464.         case LOOK_FOR_HOST:
  465.             if (*cp == '@' || *cp == '<' || *cp == '$') {
  466.                 state = ERROR_STATE;
  467.                 break;
  468.             }
  469.             if (*cp == '\0')
  470.                 break;
  471.             host = cp ;
  472.             hostlen++ ;
  473.             state = IN_HOST ;
  474.             break ;
  475.         case IN_HOST:
  476.             switch (*cp) {
  477.             case '\0':
  478.                 state = AFTER_HOST ;        /* found user@host */
  479.                 break ;
  480.             case '@':
  481.                 state = ERROR_STATE ;        /* user@host@? */
  482.                 break ;
  483.             case '<':
  484.                 state = LOOK_FOR_FROM ;        /* fromname follows */
  485.                 break ;
  486.             case '$':
  487.                 state = LOOK_FOR_MSGID ;    /* message id follows */
  488.                 break ;
  489.             default:
  490.                 hostlen++ ;
  491.             }
  492.             break ;
  493.         case AFTER_HOST:
  494.             switch (*cp) {
  495.             case '@':
  496.                 state = ERROR_STATE ;        /* user@host @ */
  497.                 break ;
  498.             case '<':
  499.                 state = LOOK_FOR_FROM ;        /* user@host < */
  500.                 break ;
  501.             case '$':
  502.                 state = LOOK_FOR_MSGID ;    /* user@host $ */
  503.                 break ;
  504.             default:
  505.                 state = ERROR_STATE ;        /* user@host foo */
  506.             }
  507.             break ;
  508.         case LOOK_FOR_FROM:
  509.             if (*cp == '@' || *cp == '<' || *cp == '$') {
  510.                 state = ERROR_STATE;
  511.                 break;
  512.             }
  513.             if (*cp == '\0')
  514.                 break;
  515.             from = cp ;
  516.             fromlen++ ;
  517.             state = IN_FROM ;
  518.             break ;
  519.         case IN_FROM:
  520.             switch (*cp) {
  521.             case '\0':
  522.                 state = AFTER_FROM ;        /* user@host <foo */
  523.                 break ;
  524.             case '<':
  525.                 state = ERROR_STATE ;        /* user@host <foo< */
  526.                 break ;
  527.             case '$':
  528.                 state = LOOK_FOR_MSGID ;    /* message id follows */
  529.                 break ;
  530.             default:
  531.                 fromlen++ ;
  532.             }
  533.             break ;
  534.         case AFTER_FROM:
  535.             switch (*cp) {
  536.             case '@':                /* user@host <foo @ */
  537.             case '<':                /* user@host <foo < */
  538.                 state = ERROR_STATE ;
  539.                 break ;
  540.             case '$':
  541.                 state = LOOK_FOR_MSGID ;    /* user@host <foo $ */
  542.                 break ;
  543.             default:
  544.                 state = ERROR_STATE ;        /* user@host foo */
  545.             }
  546.             break ;
  547.         case LOOK_FOR_MSGID:
  548.             if (*cp == '\0')
  549.                 break;
  550.             msgid = cp ;
  551.             msgidlen++ ;
  552.             state = IN_MSGID ;
  553.             break ;
  554.         case IN_MSGID:
  555.             if (*cp == '\0')
  556.                 state = FINAL_STATE ;
  557.             else
  558.                 msgidlen++ ;
  559.             break ;
  560.         default:
  561.             /* what are we doing in this state? */
  562.             state = ERROR_STATE ;
  563.         }
  564.         if (*(cp) == '\0') {
  565.             ++i;
  566.             if (i < argc)
  567.             cp = argv[i];
  568.             else break;
  569.         }
  570.         else ++cp;
  571.     }
  572.     if (state == ERROR_STATE || state == LOOK_FOR_HOST
  573.      || state == LOOK_FOR_FROM || state == LOOK_FOR_MSGID)
  574.     return -1 ;        /* syntax error */
  575.  
  576.     if ((m->to = malloc(userlen + hostlen + 2)) == NULLCHAR)
  577.         return -1 ;        /* no room for to address */
  578.  
  579.     strncpy(m->to, user, userlen) ;
  580.     m->to[userlen] = '\0' ;
  581.     
  582.     if (hostlen) {
  583.         m->to[userlen] = '@' ;
  584.         strncpy(m->to + userlen + 1, host, hostlen) ;
  585.         m->to[userlen + hostlen + 1] = '\0' ;
  586.     }
  587.     if (fromlen) {
  588.         if ((m->tofrom = malloc(fromlen + 1)) == NULLCHAR) {
  589.             free(m->to) ;
  590.             m->to = NULLCHAR ;
  591.             return -1 ;
  592.         }
  593.         strncpy(m->tofrom, from, fromlen) ;
  594.         m->tofrom[fromlen] = '\0' ;
  595.     }
  596.     if (msgidlen) {
  597.         if ((m->tomsgid = malloc(msgidlen + 1)) == NULLCHAR) {
  598.             free(m->to) ;
  599.             m->to = NULLCHAR ;
  600.             free(m->tofrom) ;
  601.             m->tofrom = NULLCHAR ;
  602.             return -1 ;
  603.         }
  604.         strncpy(m->tomsgid, msgid, msgidlen) ;
  605.         m->tomsgid[msgidlen] = '\0' ;
  606.     }
  607.     return 0 ;
  608. }
  609.  
  610. /* This opens the data file and writes the mail header into it.
  611.  * Returns 0 if OK, and -1 if not.
  612.  */
  613. static int
  614. mbx_data(m)
  615. struct mbx *m ;
  616. {
  617.     time_t t, time() ;
  618.     char *ptime() ;
  619.     extern FILE *tmpfile();
  620.     extern long get_msgid() ;
  621.     
  622.     if ((m->tfile = tmpfile()) == NULLFILE)
  623.         return -1 ;
  624.     time(&t) ;
  625.     fprintf(m->tfile,"Date: %s",ptime(&t)) ;
  626.     if (m->tomsgid)
  627.         fprintf(m->tfile,"Message-Id: <%s@%s.bbs>\n", m->tomsgid, m->name) ;
  628.     else
  629.         fprintf(m->tfile,"Message-Id: <%ld@%s>\n",get_msgid(),Hostname);
  630.     fprintf(m->tfile,"From: %s%%%s.bbs@%s\n",
  631.             m->tofrom ? m->tofrom : m->name, m->name, Hostname) ;
  632.     fprintf(m->tfile,"To: %s\n",m->to) ;
  633.     fprintf(m->tfile,"Subject: %s\n",m->line) ;
  634.     if (!isspace(m->stype))
  635.         fprintf(m->tfile,"X-BBS-Msg-Type: %c\n", m->stype) ;
  636.     fprintf(m->tfile,"\n") ;
  637.     
  638.     return 0 ;
  639. }
  640.  
  641.